﻿using zijian666.WorkScheduler.Defaults;
using zijian666.WorkScheduler.Defines;
using zijian666.WorkScheduler.Abstractions;

class MyWorkManager : IWorkManager
{
    IWorkGroup[] _groups;
    WorkData[] _works;
    WorkProgress[] _progresses;
    object[] _lockers;
    public MyWorkManager()
    {
        _groups = new IWorkGroup[4];
        _works = [];
        _progresses = [];
        _lockers = [];
        for (int i = 0; i < _groups.Length; i++)
        {
            if (_groups[i] is null)
            {
                _groups[i] = (new WorkGroup("gourp" + i, i * 2 + 1));
            }
        }

        AppendData(100);
    }

    public void AppendData(int count)
    {
        if (_works.Length + count > 10000)
        {
            throw new InvalidOperationException("数据量过大");
        }
        var works = new WorkData[_works.Length + count];
        var progresses = new WorkProgress[works.Length];
        var lockers = new object[works.Length];

        Array.ConstrainedCopy(_works, 0, works, 0, _works.Length);
        Array.ConstrainedCopy(_progresses, 0, progresses, 0, _progresses.Length);
        Array.ConstrainedCopy(_lockers, 0, lockers, 0, _lockers.Length);

        for (int i = 0; i < works.Length; i++)
        {
            if (!works[i].IsEmpty)
            {
                continue;
            }
            works[i] = (new WorkData
            {
                Id = i.ToString(),
                PlanTime = DateTimeOffset.Now.AddMilliseconds(Random.Shared.Next(1000, 3 * 1000)),
                Group = _groups[Random.Shared.Next(0, _groups.Length)],
                Status = WorkStatus.Pending,
                Ticket = null,
                Arguments = Random.Shared.Next(1000, 3000) // 延迟时间
            });
            lockers[i] ??= new object();
        }
        _works = works;
        _progresses = progresses;
        _lockers = lockers;

    }


    public Task<ICollection<WorkData>> GetPendingWorks(DateTimeOffset planTime, int limit, CancellationToken cancellation = default)
    {
        var result = _works.Where(x => x.PlanTime <= planTime && x.Status == WorkStatus.Pending).Take(limit).ToList();
        return Task.FromResult((ICollection<WorkData>)result);
    }

    public Task<WorkData> TryLock(string ticket, WorkData work, CancellationToken cancellation = default)
    {
        var index = int.Parse(work.Id);

        lock (this)
        {
            ref var curr = ref _works[index];
            if (_works.Count(x => x.Group == work.Group && x.Status == WorkStatus.Running) >= work.Group.MaxConcurrency)
            {
                return Task.FromResult(curr);
            }
            if (curr.Status is WorkStatus.Pending)
            {
                curr = work with { Status = WorkStatus.Running, Ticket = ticket };
            }
            return Task.FromResult(curr);
        }
    }

    public Task<WorkData> Report(WorkProgress progress, CancellationToken cancellation = default)
    {
        var index = int.Parse(progress.Work.Id);
        lock (_lockers[index])
        {
            ref var work = ref _works[index];
            _progresses[index] = progress;
            if (work.Status != progress.CurrentStatus)
            {
                var ticket = progress.CurrentStatus.IsCompleted() ? null : work.Ticket;
                work = work with { Status = progress.CurrentStatus, Ticket = ticket };
            }
            return Task.FromResult(work);
        }
    }

    public override string ToString()
    {
        return $" 总: {_works.Count(x => x.Status is WorkStatus.Running)} / {_works.Count(x => x.Status.IsCompleted())} / {_works.Length}, 分组: {string.Join(" ;", _works.GroupBy(x => x.Group).OrderBy(x => x.Key.Id).Select(x => $"[{x.Key.Id}]{x.Count(x => x.Status is WorkStatus.Running)}/{x.Key.MaxConcurrency},{x.Count(x => x.Status.IsCompleted())}/{x.Count()}"))}";
    }

    public WorkData GetWork(string id)
    {
        return _works.FirstOrDefault(x => x.Id == id);
    }
}
